//! Меш из триугольников
class Mesh {

// Дадим доступ классу Object для быстрого построения мировых данных
friend class Object;

protected: // Структура

	#pragma pack (push,0)
	
	//! Структура описывающая вершину
	struct Vertex {
		
		//! Позиция
		vec3 position;
		
		//! Индекс кости в скелете (-1 нет привязки к кости)
		short bone;
		
		//! Сравнение двух вершин
		const bool operator == (const Vertex& v) const {
			return (bone == v.bone) && (position == v.position);
		}
		
	};

	#pragma pack (pop)
	
	//! Массив вершин
	vector <Vertex> _vertex;
	
	//! Массив нормалей
	vector <vec3> _normal;
	
	//! Массив текстурных координат
	vector <vec2> _texcoord;

	//! Грань (треугольник) (индексы ее формирующие)
	class Face{
	public:
	
		//! Индекс в массиве _vertex для каждой из вершин грани
		unsigned short vertex[3];
		
		//! Индекс в массиве _normal для каждой из вершин грани
		unsigned short normal[3];
		
		//! Индекс в массиве _texcoord для каждой из вершин грани
		unsigned short texcoord[3];
	
	};

	//! Массив граней
	vector <Face> _face;
	
protected: // Конструктор меша

	//! Маркер координат
	//* марекры используются как значения для формирования вершин 
	//* при конструировании грани, изменить значения маркеров можно
	//* методами vertex, normal, texcoord, bone
	vec3 _v; 
	
	//! Маркер нормали
	vec3 _n;
	
	//! Маркер координат в текстуре
	vec2 _t;
	
	//! Маркер кости
	short _b;
	
	//! Счетчик вершин (кода введено 3 вершины добавляет фейс в мещ)
	int  _i;

	//! Вершины подготавлеваемого фейса
	Vertex _vf[3]; 
	
	//! Нормали подготавливаемого фейса
	vec3 _nf[3]; 
	
	//! Текстурные координаты подготавливаемого фейса
	vec2 _tf[3]; 
	
	//! Флаг сигнализирующий, что меш был изменен
	//* Какбы наменет модели, что требуется обновление мировых "параметров"
	bool _update;
	
public:

	//! Устанавливает значения маркера координат и добавляет вершину в подготовительную грань
	//* Логика схожа с тем что было в OpenGL 1.x между begin и end
	//* при помощи ф-ций normal,texcoord, bone устанавливаем значения маркеров
	//* затем вызываем vertex который установит маркер веришны а также
	//* из полученных значений сформирует вершину и положит в накопитель
	//* Как только накопится 3 вершины (3 раза вызвать vertex) в меш
	//* будет добавлен грань. 
	//* Также отмечу, что индексы грани считаются так, если в списке меше 
	//* есть такая грань, нормаль или координаты в текстуре 
	//* то соотвествующий индекс будет указывать на эту запись, иначе 
	//* нужное будет добавленно. Вершина объединяет в себе индекс кости и позицию
	//* так как это максимально экономно
	void vertex(float x, float y, float z){
		_v = vec3(x,y,z);
		_vf[_i].position = _v;
		_nf[_i] = _n;
		_tf[_i] = _t;
		_vf[_i].bone = _b;
		_i++;
		if (_i>=3) {
			_i=0;
			Face f;
			for (int i=0;i!=3;i++){
			
				unsigned int j;
				// calculate vertex index
				for (j=0;j!=_vertex.size();j++)
					if (_vf[i] == _vertex[j])
						break;
				if (j>=_vertex.size())
					_vertex.push_back(_vf[i]);
				f.vertex[i] = j;

				// calculate normal index
				for (j=0;j!=_normal.size();j++)
					if (_nf[i] == _normal[j])
						break;
				if (j>=_normal.size())
					_normal.push_back(_nf[i]);
				f.normal[i] = j;
				
				// calculate texcoord index
				for (j=0;j!=_texcoord.size();j++)
					if (_tf[i] == _texcoord[j])
						break;
				if (j>=_texcoord.size())
					_texcoord.push_back(_tf[i]);
				f.texcoord[i] = j;
				
			}
			_face.push_back(f);
			_update = true;
		}
	}

	void vertex(const vec3& v){
		_v = v;
		_vf[_i].position = _v;
		_nf[_i] = _n;
		_tf[_i] = _t;
		_vf[_i].bone = _b;
		_i++;
		if (_i>=3) {
			_i=0;
			Face f;
			for (int i=0;i!=3;i++){
				unsigned int j;
				// calculate vertex index
				for (j=0;j!=_vertex.size();j++)
					if (_vf[i] == _vertex[j])
						break;
				if (j>=_vertex.size())
					_vertex.push_back(_vf[i]);
				f.vertex[i] = j;

				// calculate normal index
				for (j=0;j!=_normal.size();j++)
					if (_nf[i] == _normal[j])
						break;
				if (j>=_normal.size())
					_normal.push_back(_nf[i]);
				f.normal[i] = j;
				
				// calculate texcoord index
				for (j=0;j!=_texcoord.size();j++)
					if (_tf[i] == _texcoord[j])
						break;
				if (j>=_texcoord.size())
					_texcoord.push_back(_tf[i]);
				f.texcoord[i] = j;
				
			}
			_face.push_back(f);
			_update = true;
		}
	}
	
	//! Установка маркера нормали (см. vertex())
	void normal(float x, float y, float z){
		_n = vec3(x,y,z);
	}

	void normal(const vec3& v){
		_n = v;
	}
	
	//! Установка маркера текстурных координат (см. vertex())
	void texcoord(float x, float y){
		_t = vec2(x,y);
	}

	void texcoord(const vec2& v){
		_t = v;
	}
	
	//! Установка маркера кости (см. vertex())
	void bone(int n){
		_b=n;
	}
	
	//! Сброс счетчика и маркеров
	void reset_constructor(){
		_i=0;
		_v=vec3(0,0,0);
		_n=vec3(0,0,0);
		_t=vec2(0,0);
		_b=-1;
	}
	
	//! Очистка меша
	void clear(){
		_i=0;
		_v=vec3(0,0,0);
		_n=vec3(0,0,0);
		_t=vec2(0,0);
		_b=-1;
		_update = true;
		_vertex.clear();
		_normal.clear();
		_texcoord.clear();
		_face.clear();
	}
	
public: // Инициализация

	Mesh(){
		_update = false;
		_v=vec3(0,0,0);
		_n=vec3(0,0,0);
		_t=vec2(0,0);
		_b=-1;
		_i=0;
	}
	
};

